home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / vid_x.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  28KB  |  1,200 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // vid_x.c -- general x video driver
  21.  
  22. #define _BSD
  23.  
  24.  
  25. #include <ctype.h>
  26. #include <sys/time.h>
  27. #include <sys/types.h>
  28. #include <unistd.h>
  29. #include <signal.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <sys/ipc.h>
  34. #include <sys/shm.h>
  35. #include <X11/Xlib.h>
  36. #include <X11/Xutil.h>
  37. #include <X11/Xatom.h>
  38. #include <X11/keysym.h>
  39. #include <X11/extensions/XShm.h>
  40.  
  41. #include "quakedef.h"
  42. #include "d_local.h"
  43.  
  44. cvar_t        _windowed_mouse = {"_windowed_mouse","0", true};
  45. cvar_t        m_filter = {"m_filter","0", true};
  46. float old_windowed_mouse;
  47.  
  48. qboolean        mouse_avail;
  49. int             mouse_buttons=3;
  50. int             mouse_oldbuttonstate;
  51. int             mouse_buttonstate;
  52. float   mouse_x, mouse_y;
  53. float   old_mouse_x, old_mouse_y;
  54. int p_mouse_x;
  55. int p_mouse_y;
  56. int ignorenext;
  57. int bits_per_pixel;
  58.  
  59. typedef struct
  60. {
  61.     int input;
  62.     int output;
  63. } keymap_t;
  64.  
  65. viddef_t vid; // global video state
  66. unsigned short d_8to16table[256];
  67.  
  68. int        num_shades=32;
  69.  
  70. int    d_con_indirect = 0;
  71.  
  72. int        vid_buffersize;
  73.  
  74. static qboolean            doShm;
  75. static Display            *x_disp;
  76. static Colormap            x_cmap;
  77. static Window            x_win;
  78. static GC                x_gc;
  79. static Visual            *x_vis;
  80. static XVisualInfo        *x_visinfo;
  81. //static XImage            *x_image;
  82.  
  83. static int                x_shmeventtype;
  84. //static XShmSegmentInfo    x_shminfo;
  85.  
  86. static qboolean            oktodraw = false;
  87.  
  88. int XShmQueryExtension(Display *);
  89. int XShmGetEventBase(Display *);
  90.  
  91. int current_framebuffer;
  92. static XImage            *x_framebuffer[2] = { 0, 0 };
  93. static XShmSegmentInfo    x_shminfo[2];
  94.  
  95. static int verbose=0;
  96.  
  97. static byte current_palette[768];
  98.  
  99. static long X11_highhunkmark;
  100. static long X11_buffersize;
  101.  
  102. int vid_surfcachesize;
  103. void *vid_surfcache;
  104.  
  105. void (*vid_menudrawfn)(void);
  106. void (*vid_menukeyfn)(int key);
  107. void VID_MenuKey (int key);
  108.  
  109. typedef unsigned short PIXEL16;
  110. typedef unsigned long PIXEL24;
  111. static PIXEL16 st2d_8to16table[256];
  112. static PIXEL24 st2d_8to24table[256];
  113. static int shiftmask_fl=0;
  114. static long r_shift,g_shift,b_shift;
  115. static unsigned long r_mask,g_mask,b_mask;
  116.  
  117. void shiftmask_init()
  118. {
  119.     unsigned int x;
  120.     r_mask=x_vis->red_mask;
  121.     g_mask=x_vis->green_mask;
  122.     b_mask=x_vis->blue_mask;
  123.     for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;
  124.     for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;
  125.     for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;
  126.     shiftmask_fl=1;
  127. }
  128.  
  129. PIXEL16 xlib_rgb16(int r,int g,int b)
  130. {
  131.     PIXEL16 p;
  132.     if(shiftmask_fl==0) shiftmask_init();
  133.     p=0;
  134.  
  135.     if(r_shift>0) {
  136.         p=(r<<(r_shift))&r_mask;
  137.     } else if(r_shift<0) {
  138.         p=(r>>(-r_shift))&r_mask;
  139.     } else p|=(r&r_mask);
  140.  
  141.     if(g_shift>0) {
  142.         p|=(g<<(g_shift))&g_mask;
  143.     } else if(g_shift<0) {
  144.         p|=(g>>(-g_shift))&g_mask;
  145.     } else p|=(g&g_mask);
  146.  
  147.     if(b_shift>0) {
  148.         p|=(b<<(b_shift))&b_mask;
  149.     } else if(b_shift<0) {
  150.         p|=(b>>(-b_shift))&b_mask;
  151.     } else p|=(b&b_mask);
  152.  
  153.     return p;
  154. }
  155.  
  156. PIXEL24 xlib_rgb24(int r,int g,int b)
  157. {
  158.     PIXEL24 p;
  159.     if(shiftmask_fl==0) shiftmask_init();
  160.     p=0;
  161.  
  162.     if(r_shift>0) {
  163.         p=(r<<(r_shift))&r_mask;
  164.     } else if(r_shift<0) {
  165.         p=(r>>(-r_shift))&r_mask;
  166.     } else p|=(r&r_mask);
  167.  
  168.     if(g_shift>0) {
  169.         p|=(g<<(g_shift))&g_mask;
  170.     } else if(g_shift<0) {
  171.         p|=(g>>(-g_shift))&g_mask;
  172.     } else p|=(g&g_mask);
  173.  
  174.     if(b_shift>0) {
  175.         p|=(b<<(b_shift))&b_mask;
  176.     } else if(b_shift<0) {
  177.         p|=(b>>(-b_shift))&b_mask;
  178.     } else p|=(b&b_mask);
  179.  
  180.     return p;
  181. }
  182.  
  183. void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
  184. {
  185.     int xi,yi;
  186.     unsigned char *src;
  187.     PIXEL16 *dest;
  188.     register int count, n;
  189.  
  190.     if( (x<0)||(y<0) )return;
  191.  
  192.     for (yi = y; yi < (y+height); yi++) {
  193.         src = &framebuf->data [yi * framebuf->bytes_per_line];
  194.  
  195.         // Duff's Device
  196.         count = width;
  197.         n = (count + 7) / 8;
  198.         dest = ((PIXEL16 *)src) + x+width - 1;
  199.         src += x+width - 1;
  200.  
  201.         switch (count % 8) {
  202.         case 0:    do {    *dest-- = st2d_8to16table[*src--];
  203.         case 7:            *dest-- = st2d_8to16table[*src--];
  204.         case 6:            *dest-- = st2d_8to16table[*src--];
  205.         case 5:            *dest-- = st2d_8to16table[*src--];
  206.         case 4:            *dest-- = st2d_8to16table[*src--];
  207.         case 3:            *dest-- = st2d_8to16table[*src--];
  208.         case 2:            *dest-- = st2d_8to16table[*src--];
  209.         case 1:            *dest-- = st2d_8to16table[*src--];
  210.                 } while (--n > 0);
  211.         }
  212.  
  213. //        for(xi = (x+width-1); xi >= x; xi--) {
  214. //            dest[xi] = st2d_8to16table[src[xi]];
  215. //        }
  216.     }
  217. }
  218.  
  219. void st3_fixup( XImage *framebuf, int x, int y, int width, int height)
  220. {
  221.     int xi,yi;
  222.     unsigned char *src;
  223.     PIXEL24 *dest;
  224.     register int count, n;
  225.  
  226.     if( (x<0)||(y<0) )return;
  227.  
  228.     for (yi = y; yi < (y+height); yi++) {
  229.         src = &framebuf->data [yi * framebuf->bytes_per_line];
  230.  
  231.         // Duff's Device
  232.         count = width;
  233.         n = (count + 7) / 8;
  234.         dest = ((PIXEL24 *)src) + x+width - 1;
  235.         src += x+width - 1;
  236.  
  237.         switch (count % 8) {
  238.         case 0:    do {    *dest-- = st2d_8to24table[*src--];
  239.         case 7:            *dest-- = st2d_8to24table[*src--];
  240.         case 6:            *dest-- = st2d_8to24table[*src--];
  241.         case 5:            *dest-- = st2d_8to24table[*src--];
  242.         case 4:            *dest-- = st2d_8to24table[*src--];
  243.         case 3:            *dest-- = st2d_8to24table[*src--];
  244.         case 2:            *dest-- = st2d_8to24table[*src--];
  245.         case 1:            *dest-- = st2d_8to24table[*src--];
  246.                 } while (--n > 0);
  247.         }
  248.  
  249. //        for(xi = (x+width-1); xi >= x; xi--) {
  250. //            dest[xi] = st2d_8to16table[src[xi]];
  251. //        }
  252.     }
  253. }
  254.  
  255.  
  256. // ========================================================================
  257. // Tragic death handler
  258. // ========================================================================
  259.  
  260. void TragicDeath(int signal_num)
  261. {
  262.     XAutoRepeatOn(x_disp);
  263.     XCloseDisplay(x_disp);
  264.     Sys_Error("This death brought to you by the number %d\n", signal_num);
  265. }
  266.  
  267. // ========================================================================
  268. // makes a null cursor
  269. // ========================================================================
  270.  
  271. static Cursor CreateNullCursor(Display *display, Window root)
  272. {
  273.     Pixmap cursormask; 
  274.     XGCValues xgc;
  275.     GC gc;
  276.     XColor dummycolour;
  277.     Cursor cursor;
  278.  
  279.     cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
  280.     xgc.function = GXclear;
  281.     gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
  282.     XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
  283.     dummycolour.pixel = 0;
  284.     dummycolour.red = 0;
  285.     dummycolour.flags = 04;
  286.     cursor = XCreatePixmapCursor(display, cursormask, cursormask,
  287.           &dummycolour,&dummycolour, 0,0);
  288.     XFreePixmap(display,cursormask);
  289.     XFreeGC(display,gc);
  290.     return cursor;
  291. }
  292.  
  293. void ResetFrameBuffer(void)
  294. {
  295.     int mem;
  296.     int pwidth;
  297.  
  298.     if (x_framebuffer[0])
  299.     {
  300.         free(x_framebuffer[0]->data);
  301.         free(x_framebuffer[0]);
  302.     }
  303.  
  304.     if (d_pzbuffer)
  305.     {
  306.         D_FlushCaches ();
  307.         Hunk_FreeToHighMark (X11_highhunkmark);
  308.         d_pzbuffer = NULL;
  309.     }
  310.     X11_highhunkmark = Hunk_HighMark ();
  311.  
  312. // alloc an extra line in case we want to wrap, and allocate the z-buffer
  313.     X11_buffersize = vid.width * vid.height * sizeof (*d_pzbuffer);
  314.  
  315.     vid_surfcachesize = D_SurfaceCacheForRes (vid.width, vid.height);
  316.  
  317.     X11_buffersize += vid_surfcachesize;
  318.  
  319.     d_pzbuffer = Hunk_HighAllocName (X11_buffersize, "video");
  320.     if (d_pzbuffer == NULL)
  321.         Sys_Error ("Not enough memory for video mode\n");
  322.  
  323.     vid_surfcache = (byte *) d_pzbuffer
  324.         + vid.width * vid.height * sizeof (*d_pzbuffer);
  325.  
  326.     D_InitCaches(vid_surfcache, vid_surfcachesize);
  327.  
  328.     pwidth = x_visinfo->depth / 8;
  329.     if (pwidth == 3) pwidth = 4;
  330.     mem = ((vid.width*pwidth+7)&~7) * vid.height;
  331.  
  332.     x_framebuffer[0] = XCreateImage(    x_disp,
  333.         x_vis,
  334.         x_visinfo->depth,
  335.         ZPixmap,
  336.         0,
  337.         malloc(mem),
  338.         vid.width, vid.height,
  339.         32,
  340.         0);
  341.  
  342.     if (!x_framebuffer[0])
  343.         Sys_Error("VID: XCreateImage failed\n");
  344.  
  345.     vid.buffer = (byte*) (x_framebuffer[0]);
  346.     vid.conbuffer = vid.buffer;
  347.  
  348. }
  349.  
  350. void ResetSharedFrameBuffers(void)
  351. {
  352.  
  353.     int size;
  354.     int key;
  355.     int minsize = getpagesize();
  356.     int frm;
  357.  
  358.     if (d_pzbuffer)
  359.     {
  360.         D_FlushCaches ();
  361.         Hunk_FreeToHighMark (X11_highhunkmark);
  362.         d_pzbuffer = NULL;
  363.     }
  364.  
  365.     X11_highhunkmark = Hunk_HighMark ();
  366.  
  367. // alloc an extra line in case we want to wrap, and allocate the z-buffer
  368.     X11_buffersize = vid.width * vid.height * sizeof (*d_pzbuffer);
  369.  
  370.     vid_surfcachesize = D_SurfaceCacheForRes (vid.width, vid.height);
  371.  
  372.     X11_buffersize += vid_surfcachesize;
  373.  
  374.     d_pzbuffer = Hunk_HighAllocName (X11_buffersize, "video");
  375.     if (d_pzbuffer == NULL)
  376.         Sys_Error ("Not enough memory for video mode\n");
  377.  
  378.     vid_surfcache = (byte *) d_pzbuffer
  379.         + vid.width * vid.height * sizeof (*d_pzbuffer);
  380.  
  381.     D_InitCaches(vid_surfcache, vid_surfcachesize);
  382.  
  383.     for (frm=0 ; frm<2 ; frm++)
  384.     {
  385.  
  386.     // free up old frame buffer memory
  387.  
  388.         if (x_framebuffer[frm])
  389.         {
  390.             XShmDetach(x_disp, &x_shminfo[frm]);
  391.             free(x_framebuffer[frm]);
  392.             shmdt(x_shminfo[frm].shmaddr);
  393.         }
  394.  
  395.     // create the image
  396.  
  397.         x_framebuffer[frm] = XShmCreateImage(    x_disp,
  398.                         x_vis,
  399.                         x_visinfo->depth,
  400.                         ZPixmap,
  401.                         0,
  402.                         &x_shminfo[frm],
  403.                         vid.width,
  404.                         vid.height );
  405.  
  406.     // grab shared memory
  407.  
  408.         size = x_framebuffer[frm]->bytes_per_line
  409.             * x_framebuffer[frm]->height;
  410.         if (size < minsize)
  411.             Sys_Error("VID: Window must use at least %d bytes\n", minsize);
  412.  
  413.         key = random();
  414.         x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
  415.         if (x_shminfo[frm].shmid==-1)
  416.             Sys_Error("VID: Could not get any shared memory\n");
  417.  
  418.         // attach to the shared memory segment
  419.         x_shminfo[frm].shmaddr =
  420.             (void *) shmat(x_shminfo[frm].shmid, 0, 0);
  421.  
  422.         printf("VID: shared memory id=%d, addr=0x%lx\n", x_shminfo[frm].shmid,
  423.             (long) x_shminfo[frm].shmaddr);
  424.  
  425.         x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
  426.  
  427.     // get the X server to attach to it
  428.  
  429.         if (!XShmAttach(x_disp, &x_shminfo[frm]))
  430.             Sys_Error("VID: XShmAttach() failed\n");
  431.         XSync(x_disp, 0);
  432.         shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
  433.  
  434.     }
  435.  
  436. }
  437.  
  438. // Called at startup to set up translation tables, takes 256 8 bit RGB values
  439. // the palette data will go away after the call, so it must be copied off if
  440. // the video driver will need it again
  441.  
  442. void    VID_Init (unsigned char *palette)
  443. {
  444.  
  445.    int pnum, i;
  446.    XVisualInfo template;
  447.    int num_visuals;
  448.    int template_mask;
  449.    
  450.    ignorenext=0;
  451.    vid.width = 320;
  452.    vid.height = 200;
  453.    vid.maxwarpwidth = WARP_WIDTH;
  454.    vid.maxwarpheight = WARP_HEIGHT;
  455.    vid.numpages = 2;
  456.    vid.colormap = host_colormap;
  457.    //    vid.cbits = VID_CBITS;
  458.    //    vid.grades = VID_GRADES;
  459.    vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
  460.    
  461.     srandom(getpid());
  462.  
  463.     verbose=COM_CheckParm("-verbose");
  464.  
  465. // open the display
  466.     x_disp = XOpenDisplay(0);
  467.     if (!x_disp)
  468.     {
  469.         if (getenv("DISPLAY"))
  470.             Sys_Error("VID: Could not open display [%s]\n",
  471.                 getenv("DISPLAY"));
  472.         else
  473.             Sys_Error("VID: Could not open local display\n");
  474.     }
  475.  
  476. // catch signals so i can turn on auto-repeat
  477.  
  478.     {
  479.         struct sigaction sa;
  480.         sigaction(SIGINT, 0, &sa);
  481.         sa.sa_handler = TragicDeath;
  482.         sigaction(SIGINT, &sa, 0);
  483.         sigaction(SIGTERM, &sa, 0);
  484.     }
  485.  
  486.     XAutoRepeatOff(x_disp);
  487.  
  488. // for debugging only
  489.     XSynchronize(x_disp, True);
  490.  
  491. // check for command-line window size
  492.     if ((pnum=COM_CheckParm("-winsize")))
  493.     {
  494.         if (pnum >= com_argc-2)
  495.             Sys_Error("VID: -winsize <width> <height>\n");
  496.         vid.width = Q_atoi(com_argv[pnum+1]);
  497.         vid.height = Q_atoi(com_argv[pnum+2]);
  498.         if (!vid.width || !vid.height)
  499.             Sys_Error("VID: Bad window width/height\n");
  500.     }
  501.     if ((pnum=COM_CheckParm("-width"))) {
  502.         if (pnum >= com_argc-1)
  503.             Sys_Error("VID: -width <width>\n");
  504.         vid.width = Q_atoi(com_argv[pnum+1]);
  505.         if (!vid.width)
  506.             Sys_Error("VID: Bad window width\n");
  507.     }
  508.     if ((pnum=COM_CheckParm("-height"))) {
  509.         if (pnum >= com_argc-1)
  510.             Sys_Error("VID: -height <height>\n");
  511.         vid.height = Q_atoi(com_argv[pnum+1]);
  512.         if (!vid.height)
  513.             Sys_Error("VID: Bad window height\n");
  514.     }
  515.  
  516.     template_mask = 0;
  517.  
  518. // specify a visual id
  519.     if ((pnum=COM_CheckParm("-visualid")))
  520.     {
  521.         if (pnum >= com_argc-1)
  522.             Sys_Error("VID: -visualid <id#>\n");
  523.         template.visualid = Q_atoi(com_argv[pnum+1]);
  524.         template_mask = VisualIDMask;
  525.     }
  526.  
  527. // If not specified, use default visual
  528.     else
  529.     {
  530.         int screen;
  531.         screen = XDefaultScreen(x_disp);
  532.         template.visualid =
  533.             XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
  534.         template_mask = VisualIDMask;
  535.     }
  536.  
  537. // pick a visual- warn if more than one was available
  538.     x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals);
  539.     if (num_visuals > 1)
  540.     {
  541.         printf("Found more than one visual id at depth %d:\n", template.depth);
  542.         for (i=0 ; i<num_visuals ; i++)
  543.             printf("    -visualid %d\n", (int)(x_visinfo[i].visualid));
  544.     }
  545.     else if (num_visuals == 0)
  546.     {
  547.         if (template_mask == VisualIDMask)
  548.             Sys_Error("VID: Bad visual id %d\n", template.visualid);
  549.         else
  550.             Sys_Error("VID: No visuals at depth %d\n", template.depth);
  551.     }
  552.  
  553.     if (verbose)
  554.     {
  555.         printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
  556.         printf("    screen %d\n", x_visinfo->screen);
  557.         printf("    red_mask 0x%x\n", (int)(x_visinfo->red_mask));
  558.         printf("    green_mask 0x%x\n", (int)(x_visinfo->green_mask));
  559.         printf("    blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
  560.         printf("    colormap_size %d\n", x_visinfo->colormap_size);
  561.         printf("    bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
  562.     }
  563.  
  564.     x_vis = x_visinfo->visual;
  565.  
  566. // setup attributes for main window
  567.     {
  568.        int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
  569.        XSetWindowAttributes attribs;
  570.        Colormap tmpcmap;
  571.        
  572.        tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
  573.                              x_visinfo->screen), x_vis, AllocNone);
  574.        
  575.            attribs.event_mask = StructureNotifyMask | KeyPressMask
  576.          | KeyReleaseMask | ExposureMask | PointerMotionMask |
  577.          ButtonPressMask | ButtonReleaseMask;
  578.        attribs.border_pixel = 0;
  579.        attribs.colormap = tmpcmap;
  580.  
  581. // create the main window
  582.         x_win = XCreateWindow(    x_disp,
  583.             XRootWindow(x_disp, x_visinfo->screen),
  584.             0, 0,    // x, y
  585.             vid.width, vid.height,
  586.             0, // borderwidth
  587.             x_visinfo->depth,
  588.             InputOutput,
  589.             x_vis,
  590.             attribmask,
  591.             &attribs );
  592.         XStoreName( x_disp,x_win,"xquake");
  593.  
  594.  
  595.         if (x_visinfo->class != TrueColor)
  596.             XFreeColormap(x_disp, tmpcmap);
  597.     }
  598.  
  599.     if (x_visinfo->depth == 8)
  600.     {
  601.         // create and upload the palette
  602.         if (x_visinfo->class == PseudoColor)
  603.         {
  604.             x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
  605.             VID_SetPalette(palette);
  606.             XSetWindowColormap(x_disp, x_win, x_cmap);
  607.         }
  608.     }
  609.  
  610. // inviso cursor
  611.     XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
  612.  
  613. // create the GC
  614.     {
  615.         XGCValues xgcvalues;
  616.         int valuemask = GCGraphicsExposures;
  617.         xgcvalues.graphics_exposures = False;
  618.         x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
  619.     }
  620.  
  621. // map the window
  622.     XMapWindow(x_disp, x_win);
  623.  
  624. // wait for first exposure event
  625.     {
  626.         XEvent event;
  627.         do
  628.         {
  629.             XNextEvent(x_disp, &event);
  630.             if (event.type == Expose && !event.xexpose.count)
  631.                 oktodraw = true;
  632.         } while (!oktodraw);
  633.     }
  634. // now safe to draw
  635.  
  636. // even if MITSHM is available, make sure it's a local connection
  637.     if (XShmQueryExtension(x_disp))
  638.     {
  639.         char *displayname;
  640.         doShm = true;
  641.         displayname = (char *) getenv("DISPLAY");
  642.         if (displayname)
  643.         {
  644.             char *d = displayname;
  645.             while (*d && (*d != ':')) d++;
  646.             if (*d) *d = 0;
  647.             if (!(!strcasecmp(displayname, "unix") || !*displayname))
  648.                 doShm = false;
  649.         }
  650.     }
  651.  
  652.     if (doShm)
  653.     {
  654.         x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion;
  655.         ResetSharedFrameBuffers();
  656.     }
  657.     else
  658.         ResetFrameBuffer();
  659.  
  660.     current_framebuffer = 0;
  661.     vid.rowbytes = x_framebuffer[0]->bytes_per_line;
  662.     vid.buffer = x_framebuffer[0]->data;
  663.     vid.direct = 0;
  664.     vid.conbuffer = x_framebuffer[0]->data;
  665.     vid.conrowbytes = vid.rowbytes;
  666.     vid.conwidth = vid.width;
  667.     vid.conheight = vid.height;
  668.     vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
  669.  
  670. //    XSynchronize(x_disp, False);
  671.  
  672. }
  673.  
  674. void VID_ShiftPalette(unsigned char *p)
  675. {
  676.     VID_SetPalette(p);
  677. }
  678.  
  679.  
  680.  
  681. void VID_SetPalette(unsigned char *palette)
  682. {
  683.  
  684.     int i;
  685.     XColor colors[256];
  686.  
  687.     for(i=0;i<256;i++) {
  688.         st2d_8to16table[i]= xlib_rgb16(palette[i*3], palette[i*3+1],palette[i*3+2]);
  689.         st2d_8to24table[i]= xlib_rgb24(palette[i*3], palette[i*3+1],palette[i*3+2]);
  690.     }
  691.  
  692.     if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
  693.     {
  694.         if (palette != current_palette)
  695.             memcpy(current_palette, palette, 768);
  696.         for (i=0 ; i<256 ; i++)
  697.         {
  698.             colors[i].pixel = i;
  699.             colors[i].flags = DoRed|DoGreen|DoBlue;
  700.             colors[i].red = palette[i*3] * 257;
  701.             colors[i].green = palette[i*3+1] * 257;
  702.             colors[i].blue = palette[i*3+2] * 257;
  703.         }
  704.         XStoreColors(x_disp, x_cmap, colors, 256);
  705.     }
  706.  
  707. }
  708.  
  709. // Called at shutdown
  710.  
  711. void    VID_Shutdown (void)
  712. {
  713.     Con_Printf("VID_Shutdown\n");
  714.     XAutoRepeatOn(x_disp);
  715.     XCloseDisplay(x_disp);
  716. }
  717.  
  718. int XLateKey(XKeyEvent *ev)
  719. {
  720.  
  721.     int key;
  722.     char buf[64];
  723.     KeySym keysym;
  724.  
  725.     key = 0;
  726.  
  727.     XLookupString(ev, buf, sizeof buf, &keysym, 0);
  728.  
  729.     switch(keysym)
  730.     {
  731.         case XK_KP_Page_Up:
  732.         case XK_Page_Up:     key = K_PGUP; break;
  733.  
  734.         case XK_KP_Page_Down:
  735.         case XK_Page_Down:     key = K_PGDN; break;
  736.  
  737.         case XK_KP_Home:
  738.         case XK_Home:     key = K_HOME; break;
  739.  
  740.         case XK_KP_End:
  741.         case XK_End:     key = K_END; break;
  742.  
  743.         case XK_KP_Left:
  744.         case XK_Left:     key = K_LEFTARROW; break;
  745.  
  746.         case XK_KP_Right:
  747.         case XK_Right:    key = K_RIGHTARROW;        break;
  748.  
  749.         case XK_KP_Down:
  750.         case XK_Down:     key = K_DOWNARROW; break;
  751.  
  752.         case XK_KP_Up:
  753.         case XK_Up:         key = K_UPARROW;     break;
  754.  
  755.         case XK_Escape: key = K_ESCAPE;        break;
  756.  
  757.         case XK_KP_Enter:
  758.         case XK_Return: key = K_ENTER;         break;
  759.  
  760.         case XK_Tab:        key = K_TAB;             break;
  761.  
  762.         case XK_F1:         key = K_F1;                break;
  763.  
  764.         case XK_F2:         key = K_F2;                break;
  765.  
  766.         case XK_F3:         key = K_F3;                break;
  767.  
  768.         case XK_F4:         key = K_F4;                break;
  769.  
  770.         case XK_F5:         key = K_F5;                break;
  771.  
  772.         case XK_F6:         key = K_F6;                break;
  773.  
  774.         case XK_F7:         key = K_F7;                break;
  775.  
  776.         case XK_F8:         key = K_F8;                break;
  777.  
  778.         case XK_F9:         key = K_F9;                break;
  779.  
  780.         case XK_F10:        key = K_F10;             break;
  781.  
  782.         case XK_F11:        key = K_F11;             break;
  783.  
  784.         case XK_F12:        key = K_F12;             break;
  785.  
  786.         case XK_BackSpace: key = K_BACKSPACE; break;
  787.  
  788.         case XK_KP_Delete:
  789.         case XK_Delete: key = K_DEL; break;
  790.  
  791.         case XK_Pause:    key = K_PAUSE;         break;
  792.  
  793.         case XK_Shift_L:
  794.         case XK_Shift_R:    key = K_SHIFT;        break;
  795.  
  796.         case XK_Execute: 
  797.         case XK_Control_L: 
  798.         case XK_Control_R:    key = K_CTRL;         break;
  799.  
  800.         case XK_Alt_L:    
  801.         case XK_Meta_L: 
  802.         case XK_Alt_R:    
  803.         case XK_Meta_R: key = K_ALT;            break;
  804.  
  805.         case XK_KP_Begin: key = K_AUX30;    break;
  806.  
  807.         case XK_Insert:
  808.         case XK_KP_Insert: key = K_INS; break;
  809.  
  810.         case XK_KP_Multiply: key = '*'; break;
  811.         case XK_KP_Add: key = '+'; break;
  812.         case XK_KP_Subtract: key = '-'; break;
  813.         case XK_KP_Divide: key = '/'; break;
  814.  
  815. #if 0
  816.         case 0x021: key = '1';break;/* [!] */
  817.         case 0x040: key = '2';break;/* [@] */
  818.         case 0x023: key = '3';break;/* [#] */
  819.         case 0x024: key = '4';break;/* [$] */
  820.         case 0x025: key = '5';break;/* [%] */
  821.         case 0x05e: key = '6';break;/* [^] */
  822.         case 0x026: key = '7';break;/* [&] */
  823.         case 0x02a: key = '8';break;/* [*] */
  824.         case 0x028: key = '9';;break;/* [(] */
  825.         case 0x029: key = '0';break;/* [)] */
  826.         case 0x05f: key = '-';break;/* [_] */
  827.         case 0x02b: key = '=';break;/* [+] */
  828.         case 0x07c: key = '\'';break;/* [|] */
  829.         case 0x07d: key = '[';break;/* [}] */
  830.         case 0x07b: key = ']';break;/* [{] */
  831.         case 0x022: key = '\'';break;/* ["] */
  832.         case 0x03a: key = ';';break;/* [:] */
  833.         case 0x03f: key = '/';break;/* [?] */
  834.         case 0x03e: key = '.';break;/* [>] */
  835.         case 0x03c: key = ',';break;/* [<] */
  836. #endif
  837.  
  838.         default:
  839.             key = *(unsigned char*)buf;
  840.             if (key >= 'A' && key <= 'Z')
  841.                 key = key - 'A' + 'a';
  842. //            fprintf(stdout, "case 0x0%x: key = ___;break;/* [%c] */\n", keysym);
  843.             break;
  844.     } 
  845.  
  846.     return key;
  847. }
  848.  
  849. struct
  850. {
  851.     int key;
  852.     int down;
  853. } keyq[64];
  854. int keyq_head=0;
  855. int keyq_tail=0;
  856.  
  857. int config_notify=0;
  858. int config_notify_width;
  859. int config_notify_height;
  860.                               
  861. void GetEvent(void)
  862. {
  863.     XEvent x_event;
  864.     int b;
  865.    
  866.     XNextEvent(x_disp, &x_event);
  867.     switch(x_event.type) {
  868.     case KeyPress:
  869.         keyq[keyq_head].key = XLateKey(&x_event.xkey);
  870.         keyq[keyq_head].down = true;
  871.         keyq_head = (keyq_head + 1) & 63;
  872.         break;
  873.     case KeyRelease:
  874.         keyq[keyq_head].key = XLateKey(&x_event.xkey);
  875.         keyq[keyq_head].down = false;
  876.         keyq_head = (keyq_head + 1) & 63;
  877.         break;
  878.  
  879.     case MotionNotify:
  880.         if (_windowed_mouse.value) {
  881.             mouse_x = (float) ((int)x_event.xmotion.x - (int)(vid.width/2));
  882.             mouse_y = (float) ((int)x_event.xmotion.y - (int)(vid.height/2));
  883. //printf("m: x=%d,y=%d, mx=%3.2f,my=%3.2f\n", 
  884. //    x_event.xmotion.x, x_event.xmotion.y, mouse_x, mouse_y);
  885.  
  886.             /* move the mouse to the window center again */
  887.             XSelectInput(x_disp,x_win,StructureNotifyMask|KeyPressMask
  888.                 |KeyReleaseMask|ExposureMask
  889.                 |ButtonPressMask
  890.                 |ButtonReleaseMask);
  891.             XWarpPointer(x_disp,None,x_win,0,0,0,0, 
  892.                 (vid.width/2),(vid.height/2));
  893.             XSelectInput(x_disp,x_win,StructureNotifyMask|KeyPressMask
  894.                 |KeyReleaseMask|ExposureMask
  895.                 |PointerMotionMask|ButtonPressMask
  896.                 |ButtonReleaseMask);
  897.         } else {
  898.             mouse_x = (float) (x_event.xmotion.x-p_mouse_x);
  899.             mouse_y = (float) (x_event.xmotion.y-p_mouse_y);
  900.             p_mouse_x=x_event.xmotion.x;
  901.             p_mouse_y=x_event.xmotion.y;
  902.         }
  903.         break;
  904.  
  905.     case ButtonPress:
  906.         b=-1;
  907.         if (x_event.xbutton.button == 1)
  908.             b = 0;
  909.         else if (x_event.xbutton.button == 2)
  910.             b = 2;
  911.         else if (x_event.xbutton.button == 3)
  912.             b = 1;
  913.         if (b>=0)
  914.             mouse_buttonstate |= 1<<b;
  915.         break;
  916.  
  917.     case ButtonRelease:
  918.         b=-1;
  919.         if (x_event.xbutton.button == 1)
  920.             b = 0;
  921.         else if (x_event.xbutton.button == 2)
  922.             b = 2;
  923.         else if (x_event.xbutton.button == 3)
  924.             b = 1;
  925.         if (b>=0)
  926.             mouse_buttonstate &= ~(1<<b);
  927.         break;
  928.     
  929.     case ConfigureNotify:
  930. //printf("config notify\n");
  931.         config_notify_width = x_event.xconfigure.width;
  932.         config_notify_height = x_event.xconfigure.height;
  933.         config_notify = 1;
  934.         break;
  935.  
  936.     default:
  937.         if (doShm && x_event.type == x_shmeventtype)
  938.             oktodraw = true;
  939.     }
  940.    
  941.     if (old_windowed_mouse != _windowed_mouse.value) {
  942.         old_windowed_mouse = _windowed_mouse.value;
  943.  
  944.         if (!_windowed_mouse.value) {
  945.             /* ungrab the pointer */
  946.             XUngrabPointer(x_disp,CurrentTime);
  947.         } else {
  948.             /* grab the pointer */
  949.             XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
  950.                 GrabModeAsync,x_win,None,CurrentTime);
  951.         }
  952.     }
  953. }
  954.  
  955. // flushes the given rectangles from the view buffer to the screen
  956.  
  957. void    VID_Update (vrect_t *rects)
  958. {
  959.     vrect_t full;
  960.  
  961. // if the window changes dimension, skip this frame
  962.  
  963.     if (config_notify)
  964.     {
  965.         fprintf(stderr, "config notify\n");
  966.         config_notify = 0;
  967.         vid.width = config_notify_width & ~7;
  968.         vid.height = config_notify_height;
  969.         if (doShm)
  970.             ResetSharedFrameBuffers();
  971.         else
  972.             ResetFrameBuffer();
  973.         vid.rowbytes = x_framebuffer[0]->bytes_per_line;
  974.         vid.buffer = x_framebuffer[current_framebuffer]->data;
  975.         vid.conbuffer = vid.buffer;
  976.         vid.conwidth = vid.width;
  977.         vid.conheight = vid.height;
  978.         vid.conrowbytes = vid.rowbytes;
  979.         vid.recalc_refdef = 1;                // force a surface cache flush
  980.         Con_CheckResize();
  981.         Con_Clear_f();
  982.         return;
  983.     }
  984.  
  985.     // force full update if not 8bit
  986.     if (x_visinfo->depth != 8) {
  987.         extern int scr_fullupdate;
  988.  
  989.         scr_fullupdate = 0;
  990.     }
  991.  
  992.  
  993.     if (doShm)
  994.     {
  995.  
  996.         while (rects)
  997.         {
  998.             if (x_visinfo->depth == 16)
  999.                 st2_fixup( x_framebuffer[current_framebuffer], 
  1000.                     rects->x, rects->y, rects->width,
  1001.                     rects->height);
  1002.             else if (x_visinfo->depth == 24)
  1003.                 st3_fixup( x_framebuffer[current_framebuffer], 
  1004.                     rects->x, rects->y, rects->width,
  1005.                     rects->height);
  1006.             if (!XShmPutImage(x_disp, x_win, x_gc,
  1007.                 x_framebuffer[current_framebuffer], rects->x, rects->y,
  1008.                 rects->x, rects->y, rects->width, rects->height, True))
  1009.                     Sys_Error("VID_Update: XShmPutImage failed\n");
  1010.             oktodraw = false;
  1011.             while (!oktodraw) GetEvent();
  1012.             rects = rects->pnext;
  1013.         }
  1014.         current_framebuffer = !current_framebuffer;
  1015.         vid.buffer = x_framebuffer[current_framebuffer]->data;
  1016.         vid.conbuffer = vid.buffer;
  1017.         XSync(x_disp, False);
  1018.     }
  1019.     else
  1020.     {
  1021.         while (rects)
  1022.         {
  1023.             if (x_visinfo->depth == 16)
  1024.                 st2_fixup( x_framebuffer[current_framebuffer], 
  1025.                     rects->x, rects->y, rects->width,
  1026.                     rects->height);
  1027.             else if (x_visinfo->depth == 24)
  1028.                 st3_fixup( x_framebuffer[current_framebuffer], 
  1029.                     rects->x, rects->y, rects->width,
  1030.                     rects->height);
  1031.             XPutImage(x_disp, x_win, x_gc, x_framebuffer[0], rects->x,
  1032.                 rects->y, rects->x, rects->y, rects->width, rects->height);
  1033.             rects = rects->pnext;
  1034.         }
  1035.         XSync(x_disp, False);
  1036.     }
  1037.  
  1038. }
  1039.  
  1040. static int dither;
  1041.  
  1042. void VID_DitherOn(void)
  1043. {
  1044.     if (dither == 0)
  1045.     {
  1046.         vid.recalc_refdef = 1;
  1047.         dither = 1;
  1048.     }
  1049. }
  1050.  
  1051. void VID_DitherOff(void)
  1052. {
  1053.     if (dither)
  1054.     {
  1055.         vid.recalc_refdef = 1;
  1056.         dither = 0;
  1057.     }
  1058. }
  1059.  
  1060. int Sys_OpenWindow(void)
  1061. {
  1062.     return 0;
  1063. }
  1064.  
  1065. void Sys_EraseWindow(int window)
  1066. {
  1067. }
  1068.  
  1069. void Sys_DrawCircle(int window, int x, int y, int r)
  1070. {
  1071. }
  1072.  
  1073. void Sys_DisplayWindow(int window)
  1074. {
  1075. }
  1076.  
  1077. void Sys_SendKeyEvents(void)
  1078. {
  1079. // get events from x server
  1080.     if (x_disp)
  1081.     {
  1082.         while (XPending(x_disp)) GetEvent();
  1083.         while (keyq_head != keyq_tail)
  1084.         {
  1085.             Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down);
  1086.             keyq_tail = (keyq_tail + 1) & 63;
  1087.         }
  1088.     }
  1089. }
  1090.  
  1091. #if 0
  1092. char *Sys_ConsoleInput (void)
  1093. {
  1094.  
  1095.     static char    text[256];
  1096.     int        len;
  1097.     fd_set  readfds;
  1098.     int        ready;
  1099.     struct timeval timeout;
  1100.  
  1101.     timeout.tv_sec = 0;
  1102.     timeout.tv_usec = 0;
  1103.     FD_ZERO(&readfds);
  1104.     FD_SET(0, &readfds);
  1105.     ready = select(1, &readfds, 0, 0, &timeout);
  1106.  
  1107.     if (ready>0)
  1108.     {
  1109.         len = read (0, text, sizeof(text));
  1110.         if (len >= 1)
  1111.         {
  1112.             text[len-1] = 0;    // rip off the /n and terminate
  1113.             return text;
  1114.         }
  1115.     }
  1116.  
  1117.     return 0;
  1118.     
  1119. }
  1120. #endif
  1121.  
  1122. void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
  1123. {
  1124. // direct drawing of the "accessing disk" icon isn't supported under Linux
  1125. }
  1126.  
  1127. void D_EndDirectRect (int x, int y, int width, int height)
  1128. {
  1129. // direct drawing of the "accessing disk" icon isn't supported under Linux
  1130. }
  1131.  
  1132. void IN_Init (void)
  1133. {
  1134.     Cvar_RegisterVariable (&_windowed_mouse);
  1135.     Cvar_RegisterVariable (&m_filter);
  1136.    if ( COM_CheckParm ("-nomouse") )
  1137.      return;
  1138.    mouse_x = mouse_y = 0.0;
  1139.    mouse_avail = 1;
  1140. }
  1141.  
  1142. void IN_Shutdown (void)
  1143. {
  1144.    mouse_avail = 0;
  1145. }
  1146.  
  1147. void IN_Commands (void)
  1148. {
  1149.     int i;
  1150.    
  1151.     if (!mouse_avail) return;
  1152.    
  1153.     for (i=0 ; i<mouse_buttons ; i++) {
  1154.         if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
  1155.             Key_Event (K_MOUSE1 + i, true);
  1156.  
  1157.         if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
  1158.             Key_Event (K_MOUSE1 + i, false);
  1159.     }
  1160.     mouse_oldbuttonstate = mouse_buttonstate;
  1161. }
  1162.  
  1163. void IN_Move (usercmd_t *cmd)
  1164. {
  1165.     if (!mouse_avail)
  1166.         return;
  1167.    
  1168.     if (m_filter.value) {
  1169.         mouse_x = (mouse_x + old_mouse_x) * 0.5;
  1170.         mouse_y = (mouse_y + old_mouse_y) * 0.5;
  1171.     }
  1172.  
  1173.     old_mouse_x = mouse_x;
  1174.     old_mouse_y = mouse_y;
  1175.    
  1176.     mouse_x *= sensitivity.value;
  1177.     mouse_y *= sensitivity.value;
  1178.    
  1179.     if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
  1180.         cmd->sidemove += m_side.value * mouse_x;
  1181.     else
  1182.         cl.viewangles[YAW] -= m_yaw.value * mouse_x;
  1183.     if (in_mlook.state & 1)
  1184.         V_StopPitchDrift ();
  1185.    
  1186.     if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) {
  1187.         cl.viewangles[PITCH] += m_pitch.value * mouse_y;
  1188.         if (cl.viewangles[PITCH] > 80)
  1189.             cl.viewangles[PITCH] = 80;
  1190.         if (cl.viewangles[PITCH] < -70)
  1191.             cl.viewangles[PITCH] = -70;
  1192.     } else {
  1193.         if ((in_strafe.state & 1) && noclip_anglehack)
  1194.             cmd->upmove -= m_forward.value * mouse_y;
  1195.         else
  1196.             cmd->forwardmove -= m_forward.value * mouse_y;
  1197.     }
  1198.     mouse_x = mouse_y = 0.0;
  1199. }
  1200.